package example;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Fattura {
	
	public static final String tabName = "fattura";
	
	public static final String idField = "id";
	public static final String statusField = "status";
	public static final String dataNoleggioField = "data_noleggio";
	public static final String dataRestituzioneField = "data_restituzione";
	public static final String utenteIdField = "utente_id";
	public static final String filmIdField = "film_id";
	
    public int id;

    public Utente utente; /* Copia delle informazioni dell'utente */
    public Film film; /* Devo farmi una copia del film */
    public boolean status; /* Restituito */
    public Date dataNoleggio;
    public Date dataRestituzione;

    /* Film */
    int filmId;
    int categoriaId;
    Categoria categoria;
    String titolo;
    String descrizione;
    int anno;
    Date uscita;
    double voto;
    int durata; // Minuti
    
    /* Utente */
    int utenteId;
    String codiceCarta; /* come e' fatto il codice della carta? tipo 5num+5lett+10num+5lett */
    String nome;
    String cognome;
    Date compleanno;
    String email;
    String codiceFiscale;
    String citta;
    String via;
    String recapitoTelefonico;
    
    public Fattura() {
    	
    	this.id = -1;
    	this.filmId = -1;
    	this.categoriaId = -1;
    	this.utenteId = -1;
    	
    	this.film = null;
    	this.utente = null;
    	
    }
    
    public Result validate() {
    	Result result = new Result( true, null, "" );
    	Result fr = null;
    	Result ur = null;
    	
    	if ( this.dataNoleggio == null ) {
    		result.result = false;
    		result.errorMessage += "La data di noleggio deve essere inserita. \n";
    	}
    	
    	/* Validate film */
    	if ( this.film == null ) {
    		result.result = false;
    		result.errorMessage += "Il noleggio deve essere associato ad un film valido. \n";
    	} else {
    		fr = film.validate();
    		result.errorMessage += fr.errorMessage;
    		result.result = result.result && fr.result;
    	}
    	
    	/* Validate utente */
    	if ( this.utente == null ) {
    		result.result = false;
    		result.errorMessage += "Il noleggio deve essere associato ad un utente valido. \n";
    	} else {
    		ur = utente.validate();
    		result.errorMessage += ur.errorMessage;
    		result.result = result.result && ur.result;
    	}
    	
    	return result;
    }

    
    private void set ( ResultSet rs ) throws SQLException {
    	
    	this.film = new Film();
    	this.utente = new Utente();
    	
    	/* Fattura */
    	this.id = rs.getInt( idField );
    	this.status = rs.getBoolean( statusField );
    	this.dataNoleggio = rs.getDate( dataNoleggioField );
    	this.dataRestituzione = rs.getDate( dataRestituzioneField );
    	
    	/* Film */
    	this.film.id = this.filmId = rs.getInt( filmIdField );
    	this.film.titolo = this.titolo = rs.getString( Film.titoloField );
    	this.film.categoriaId = this.categoriaId = rs.getInt( Film.categoriaIdField );
    	this.film.descrizione = this.descrizione = rs.getString( Film.descrizioneField );
    	this.film.anno = this.anno = rs.getInt( Film.annoField );
    	this.film.uscita = this.uscita = rs.getDate( Film.uscitaField );
    	this.film.voto = this.voto = rs.getDouble( Film.votoField );
    	this.film.durata = this.durata = rs.getInt( Film.durataField );
    	
    	/* User */
    	this.utente.id = this.utenteId = rs.getInt( utenteIdField );
    	this.utente.codiceCarta = this.codiceCarta = rs.getString( Utente.codiceCartaField );
    	this.utente.nome = this.nome = rs.getString( Utente.nomeField );
    	this.utente.cognome = this.cognome = rs.getString( Utente.cognomeField );
    	this.utente.compleanno = this.compleanno = rs.getDate( Utente.compleannoField );
    	this.utente.email = this.email = rs.getString( Utente.emailField );
    	this.utente.codiceFiscale = this.codiceFiscale = rs.getString( Utente.codiceFiscaleField );
    	this.utente.citta = this.citta = rs.getString( Utente.cittaField );
    	this.utente.via = this.via = rs.getString( Utente.viaField );
    	this.utente.recapitoTelefonico = this.recapitoTelefonico = rs.getString( Utente.recapitoTelefonicoField );
    }
    
    public void setFilm ( Film o ) {
    	
    	this.film = new Film();
    	this.film.set( o );
    	
    	this.filmId = o.id;
    	this.titolo = o.titolo;
    	this.categoriaId = o.categoriaId;
    	this.descrizione = o.descrizione;
    	this.anno = o.anno;
    	this.uscita = o.uscita;
    	this.voto = o.voto;
    	this.durata = o.durata;
    	this.categoria = o.categoria;
    }
    
    public void setUtente ( Utente o ) {
    	
    	this.utente = new Utente();
    	this.utente.set( o );
    	
    	this.utenteId = o.id;
    	this.codiceCarta = o.codiceCarta;
    	this.nome = o.nome;
    	this.cognome = o.cognome;
    	this.compleanno = o.compleanno;
    	this.email = o.email;
    	this.codiceFiscale = o.codiceFiscale;
    	this.citta = o.citta;
    	this.via = o.via;
    	this.recapitoTelefonico = o.recapitoTelefonico;
    }
    
    private void set ( Fattura o ) {
    	
    	this.film = new Film();
    	this.utente = new Utente();
    	
    	/* Noleggio */
    	this.id = o.id;
    	this.status = o.status;
    	this.dataNoleggio = o.dataNoleggio;
    	this.dataRestituzione = o.dataRestituzione;
    	/* Film */
    	this.film.id = this.filmId = o.filmId;
    	this.film.titolo = this.titolo = o.titolo;
    	this.film.categoriaId = this.categoriaId = o.categoriaId;
    	this.film.descrizione = this.descrizione = o.descrizione;
    	this.film.anno = this.anno = o.anno;
    	this.film.uscita = this.uscita = o.uscita;
    	this.film.voto = this.voto = o.voto;
    	this.film.durata = this.durata = o.durata;
    	this.film.categoria = this.categoria = o.categoria;
    	
    	/* User */
    	this.utente.id = this.utenteId = o.utenteId;
    	this.utente.codiceCarta = this.codiceCarta = o.codiceCarta;
    	this.utente.nome = this.nome = o.nome;
    	this.utente.cognome = this.cognome = o.cognome;
    	this.utente.compleanno = this.compleanno = o.compleanno;
    	this.utente.email = this.email = o.email;
    	this.utente.codiceFiscale = this.codiceFiscale = o.codiceFiscale;
    	this.utente.citta = this.citta = o.citta;
    	this.utente.via = this.via = o.via;
    	this.utente.recapitoTelefonico = this.recapitoTelefonico = o.recapitoTelefonico;
    	
    }

    private Result load( int id, Connection c ) {
    	// load it from DB
    	Result result = null;
    	PreparedStatement pstmt = null;
        ResultSet rs = null;
    	
    	String sqlQuery = "SELECT * FROM " + tabName + " WHERE "+ idField + " = ?";
    	
    	this.id = this.id > 0 ? this.id : id;
    	
    	try {
    		
    		c.setAutoCommit(false);
    		
			pstmt = c.prepareStatement(sqlQuery);
			pstmt.setInt(1, this.id  );
	        rs = pstmt.executeQuery();
	        
	        if ( rs.next() ) {
	        	this.set( rs );	
	        	result = new Result( true, this, "" );
	        } else {
	        	//errore, non c'era il record sul db
	        	if ( Test.DEBUG ) System.out.println("La fattura con id " + this.id + " non e' presente sul database.");
	        	result = new Result(false, null, "La fattura con id " + this.id + " non e' presente sul database.");
	        }
	        
	        rs.close();
	        pstmt.close();
	        c.commit();
	        
	        
	        
		} catch (SQLException e) {
			System.out.println( "SQL Exception: " +e.getMessage());
            result = new Result(false, null,  "SQL Exception: " +e.getMessage() + " per fattura con ID " + this.id );
        } finally {
            try{
                if( rs != null )
                    rs.close();
                if( pstmt != null )
                    pstmt.close();
            } catch(Exception e){
                System.out.println(" Rilascio risorse non riuscito: "+e.getMessage());
            }
        }
		
		return result;
    }

    public Result save( Connection c ) {
    	return save(c, true);    	
    }
    
    public Result save( Connection c, boolean validate ) {
    	Result result = null;
    	int rowAffected;
    	boolean insert;
    	
    	String query = "";
    	PreparedStatement pstmt = null;
    	ResultSet rs = null;
    	
    	int copieRimaste = 0;
    	
    	if ( validate ) {
    		result = validate();
    		if ( !result.result )
    			return result;
    	}
    	
    	try {
    		
    		c.setAutoCommit(false);
    		
    		

    		if ( this.id < 1 ) { //non e' un nuovo record
    			
    			/* TODO Prima di fare questo devo diminuire le copieRimaste del Film */
    			c.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
    			query = "SELECT " + Film.copieRimasteField + " FROM " + Film.tabName + " WHERE " + Film.idField + " = ?";
    			pstmt = c.prepareStatement(query);
    			pstmt.setInt(1, this.filmId  );
    			
    	        rs = pstmt.executeQuery();
    	        
    	        if ( rs.next() ) {
    	        	
    	        	copieRimaste = rs.getInt( Film.copieRimasteField );
    	        	if ( copieRimaste == 0 ) {
    	        		
    	        		result = new Result(false, null, "Il film con id " + this.filmId + " NON ha piu' copie rimanenti.");
        	        	if ( Test.DEBUG ) System.out.println( result.errorMessage );
    	        		
    	        		rs.close();
        		        pstmt.close();
        		        c.commit();
        		        
    	        		return result;
    	        	}
    	        	
    	        } else {
    	        	//errore, non c'era il record sul db
    	        	result = new Result(false, null, "Il film con id " + this.filmId + " non e' presente sul database.");
    	        	if ( Test.DEBUG ) System.out.println( result.errorMessage );
    	        	
    	        	rs.close();
    		        pstmt.close();
    		        c.commit();
    		        
    	        	return result;
    	        }
    			
    			query = "INSERT INTO "+ tabName +" ( " + idField + ", " + statusField + ", " + dataNoleggioField + ", " + dataRestituzioneField + ", " + filmIdField + ", " + Film.categoriaIdField + ", " + Film.titoloField + ", " + Film.descrizioneField + ", " + Film.annoField + ", " + Film.uscitaField + ", " + Film.votoField + ", " + Film.durataField + ", " + utenteIdField + ", " + Utente.codiceCartaField + ", " + Utente.nomeField + ", " + Utente.cognomeField + ", " + Utente.compleannoField + ", " + Utente.emailField + ", " + Utente.codiceFiscaleField + ", " + Utente.cittaField + ", " + Utente.viaField + ", " + Utente.recapitoTelefonicoField + "  ) VALUES (DEFAULT,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
	    		insert = true;
	    		pstmt = c.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
	    		
	    		
	    	} else { //TODO: quando status cambia e viene messo che e' stato ridato devo aumentare le copie rimanenti
	    		c.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
	    		query = "UPDATE "+ tabName +" SET " + statusField + " = ?, " + dataNoleggioField + " = ?, " + dataRestituzioneField + " = ?, " + filmIdField + " = ?, " + Film.categoriaIdField + " = ?, " + Film.titoloField + " = ?, " + Film.descrizioneField + " = ?, " + Film.annoField + " = ?, " + Film.uscitaField +  " = ?, " + Film.votoField +  " = ?, " + Film.durataField +  " = ?, " + utenteIdField +  " = ?, " + Utente.codiceCartaField +  " = ?, " + Utente.nomeField +  " = ?, " + Utente.cognomeField +  " = ?, " + Utente.compleannoField +  " = ?, " + Utente.emailField +  " = ?, " + Utente.codiceFiscaleField +  " = ?, " + Utente.cittaField +  " = ?, " + Utente.viaField +  " = ?, " + Utente.recapitoTelefonicoField + " = ? WHERE " + idField + " = ?";
	    		insert = false;
	    		pstmt = c.prepareStatement(query);
	    	}
	    	
	    	pstmt.setBoolean(1, this.status );
	    	pstmt.setDate(2, this.dataNoleggio  );
	    	pstmt.setDate(3, this.dataRestituzione  );
	    	pstmt.setInt(4, this.filmId  );
	    	pstmt.setInt(5, this.categoriaId  );
	    	pstmt.setString(6, this.titolo  );
	    	pstmt.setString(7, this.descrizione  );
	    	pstmt.setInt(8, this.anno  );
	    	pstmt.setDate(9, this.uscita  );
	    	pstmt.setDouble(10, this.voto  );
	    	pstmt.setInt(11, this.durata  );
	    	pstmt.setInt(12, this.utenteId );
	    	pstmt.setString(13, this.codiceCarta  );
	    	pstmt.setString(14, this.nome  );
	    	pstmt.setString(15, this.cognome  );
	    	pstmt.setDate(16, this.compleanno  );
	    	pstmt.setString(17, this.email  );
	    	pstmt.setString(18, this.codiceFiscale  );
	    	pstmt.setString(19, this.citta  );
	    	pstmt.setString(20, this.via  );
	    	pstmt.setString(21, this.recapitoTelefonico  );
	    	
	    	if ( this.id > 0 )
	    		pstmt.setInt(22, this.id  );
	    	
	    	rowAffected = pstmt.executeUpdate();
	    	
	    	//Aggiorno l'id del film	    	
	    	if ( rowAffected > 0 && insert ) { //TODO: CAPIRE PERCHE' NON VA!!!!!
	    		rs = pstmt.getGeneratedKeys();
	    		System.out.println("Prima di prendere id da rs ");
	    		if ( rs != null && rs.next() ) {
	    			
	    			this.id = rs.getInt(1);
		    		result = new Result(true, this, "Operazione di insert avvenuta con successo per fattura con ID " + this.id );
		    		if ( Test.DEBUG ) System.out.println( result.errorMessage );
	    		}
	    		rs.close();	
	    	}
	    	
	    	
	    	if ( rowAffected > 0 ) {
	    		
	    		result = new Result(true, this, "Operazione di " + ( insert ? " insert" : "update" ) + " avvenuta con successo per fattura con ID " + this.id );
	    		if ( insert ) {
	    			copieRimaste--;
	    			query = "UPDATE "+ Film.tabName +" SET " + Film.copieRimasteField + " = ? WHERE " + Film.idField + " = ?";
	    			pstmt = c.prepareStatement(query);
	    			pstmt.setInt(1, copieRimaste  );
	    			pstmt.setInt(2, this.filmId  );
	    			rowAffected = pstmt.executeUpdate();
	    			if ( rowAffected <= 0 ) {
	    				result = new Result(false, null, "Errore durante operazione di aggiornamento delle copie rimaste per film con ID " + this.filmId + " riguardante la fattura con ID " + this.id );
	    	    		if ( Test.DEBUG ) System.out.println( result.errorMessage );
	    	    		c.rollback(); // devo effettuare il rollback, perche' non posso inserire la fattura dato che non ho aggiornato le copieRimaste del film.
	    	    		return result;
	    			}
	    		}
	    		
	    	} else {
	    		result = new Result(false, null, "Errore durante operazione di " + ( insert ? " insert" : "update" ) + " per fattura con ID " + this.id );
	    		if ( Test.DEBUG ) System.out.println( result.errorMessage );
	    	}
	    	
	    	
	    	
	    	
	    	pstmt.close();
	    	c.commit();
	    	
	    	c.setAutoCommit(true);
	    	
	    	
	    	
    	} catch(Exception e){
    		result = new Result ( false, null, "Errore generale: " +e.getMessage() + "\nRecord non inserito per fattura con ID " + this.id );
    		if ( Test.DEBUG ) System.out.println( result.errorMessage );
            //rollback
            try{
            	System.out.println("Rollback, annullo modifiche al database");
                c.rollback();
            } catch(Exception eRollback){}
        
        } finally {
            try{
                if( rs != null )
                    rs.close();
                if( pstmt != null )
                    pstmt.close();
            } catch(Exception e){
            	result = new Result ( false, null, "Rilascio risorse non riuscito: "+e.getMessage() + "\nRecord non inserito per fattura con ID " + this.id );
            	System.out.println( result.errorMessage );
            }
        }
        return result;
    }

    public Result delete( Connection c ) {
    	String query = "";
    	PreparedStatement pstmt = null;
    	Result result = null;
    	int affectedRows = 0;
    	
    	try {
    		c.setAutoCommit(false);
    		query = "DELETE FROM " + tabName + " WHERE " + idField + " = ?";
    		pstmt = c.prepareStatement(query);
    		pstmt.setInt(1, this.id);
    		
    		affectedRows = pstmt.executeUpdate();
    		if ( affectedRows > 0 ) {
    			result = new Result ( true, null, "Record cancellato con fattura con ID " + this.id );
	    	} else {
	    		result = new Result ( false, null, "Record NON cancellato con fattura con ID " + this.id );
	    	}
    			
    		pstmt.close();
    		c.commit();

    		
    	} catch(Exception e){
            result = new Result ( false, null, "Errore generale: " +e.getMessage() + "\nRecord non cancellato per fattura con ID " + this.id );
            if ( Test.DEBUG ) System.out.println( result.errorMessage );
            // rollback
            try{
            	System.out.println("Rollback, annullo modifiche al database");
                c.rollback();
            } catch(Exception eRollback){}
        
        } finally {
            try{
                if( pstmt != null )
                    pstmt.close();
            } catch(Exception e){
            	result = new Result ( false, null, "Rilascio risorse non riuscito: " +e.getMessage() + "\nRecord non cancellato con fattura con ID " + this.id );
                System.out.println("Rilascio risorse non riuscito: "+e.getMessage());
            }
        }
        
        
    	return result;
    }

    public String statusToString() {
        if ( this.status )
            return "Si";
        else
            return "No";
    }
    
    public String toString() {
    	String ret = "";
        ret += "Noleggio numero "+ this.id + ". Status: " + statusToString() + "\n";
        
        return ret;
    }

}
